package com.ss.service.impl;


import com.ss.core.exceptions.SummerExecuteException;
import com.ss.entity.*;
import com.ss.entity.enums.SummerBackType;
import com.ss.entity.enums.SummerInstanceStatus;
import com.ss.entity.enums.SummerNodeType;
import com.ss.entity.enums.SummerRecordResult;
import com.ss.mapper.*;
import com.ss.service.support.ExecuteFlow;
import com.ss.service.support.ExecuteMember;
import com.ss.service.support.ExecuteNode;
import com.ss.service.SummerExecute;
import com.ss.service.support.SummerAppoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Author: 夏十七
 * @Date: 2019/7/24 21:19
 * @Version 1.0
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class SummerExecuteImpl implements SummerExecute {

    @Autowired
    private ExecuteFlow executeFlow;
    @Autowired
    private ExecuteNode executeNode;
    @Autowired
    private ExecuteMember executeMember;

    @Autowired
    @SuppressWarnings("all")
    private SummerInstanceMapper summerInstanceMapper;
    @Autowired
    @SuppressWarnings("all")
    private SummerNodeMapper summerNodeMapper;
    @Autowired
    @SuppressWarnings("all")
    private SummerRecordMapper summerRecordMapper;
    @Autowired
    @SuppressWarnings("all")
    private SummerAppointMemberMapper summerAppointMemberMapper;
    @Autowired
    @SuppressWarnings("all")
    private SummerAppointMemberGlobalMapper summerAppointMemberGlobalMapper;

    @Override
    public SummerAppoint start(Integer applyId, String apiPath) {
        //检测审批流是否存在
        SummerFlow summerFlow = executeFlow.getUseFlow(apiPath);
        //调用start
        return this.start(applyId,summerFlow,null);
    }


    @Override
    public SummerAppoint startToNode(Integer applyId, String apiPath, Integer nodeId) {
        //检测审批流是否存在
        SummerFlow summerFlow = executeFlow.getCrossNodeFlow(apiPath);
        //调用start
        return this.start(applyId,summerFlow,nodeId);
    }

    @Override
    public void restart(Integer applyId, String apiPath) {
        //检测审批流是否存在
        SummerFlow summerFlow = executeFlow.getUseFlow(apiPath);
        SummerInstance summerInstance = this.getInstanceByFlowIdAndApplyId(summerFlow.getId(),applyId);
        if (summerInstance == null){
            throw new SummerExecuteException("重启流程失败，实例不存在。");
        }
        //如果状态不是退回编辑
        if (!SummerInstanceStatus.BACK.equals(summerInstance.getStatus())){
            throw new SummerExecuteException("重启流程失败,该流程不在退回编辑状态。");
        }
        //重启流程。
        summerInstance.setStatus(SummerInstanceStatus.ONGOING);
        //下一个节点信息
        SummerNode node ;
        if (summerInstance.getSubmitNode()!=null){
            //获取用户指定的节点
            node = executeNode.getAppointNode(summerInstance.getSubmitNode());
        }else {
            //获取第一个节点
            node = executeNode.getFirstNode(summerFlow.getId());
        }
        //设置提交后的节点
        summerInstance.setNowNode(node.getId());
        SummerRecord summerRecord = this.createRecord(null,node, SummerRecordResult.SUBMIT, null, new SummerNodeMember("1"));
        this.saveToDb(summerInstance,summerRecord);
    }

    @Override
    public SummerAppoint pass(Integer applyId, String apiPath, String member, String opinion) {
       return this.pass(applyId,apiPath,member,opinion,null);
    }


    @Override
    public SummerAppoint passToNode(Integer applyId, String apiPath, Integer nodeId, String member, String opinion) {
        return this.pass(applyId,apiPath,member,opinion,nodeId);
    }


    @Override
    public void passToEnd(Integer applyId, String apiPath, String member, String opinion) {
        //检测审批流是否存在
        SummerFlow summerFlow = executeFlow.getUseFlow(apiPath);
        SummerInstance summerInstance = this.getInstanceByFlowIdAndApplyId(summerFlow.getId(),applyId);
        if (summerInstance == null){
            throw new SummerExecuteException("审核失败，该申请不存在");
        }
        //检测审核权限
        SummerNodeMember nodeMember = executeMember.provingAuth(summerInstance,member);
        //判断节点权限
        if (!summerInstance.getNode().getType().equals(SummerNodeType.END)){
            throw new SummerExecuteException("该节点无直接通过权限");
        }
        //为null 则是通过
        summerInstance.setStatus(SummerInstanceStatus.PASS);
        Integer auditNode = summerInstance.getNowNode();
        summerInstance.setNowNode(null);
        //新建审核记录
        SummerRecord record = this.createRecord(auditNode,null, SummerRecordResult.PASS_TO_END, opinion, nodeMember);
        this.saveToDb(summerInstance,record);
    }

    @Override
    public void fail(Integer applyId, String apiPath, String member, String opinion) {
        //检测审批流是否存在
        SummerFlow summerFlow = executeFlow.getUseFlow(apiPath);
        SummerInstance summerInstance = this.getInstanceByFlowIdAndApplyId(summerFlow.getId(),applyId);
        if (summerInstance == null){
            throw new SummerExecuteException("审核失败，该申请不存在");
        }
        //结束事件流
        summerInstance.setStatus(SummerInstanceStatus.FAIL);
        //检测审核权限
        SummerNodeMember nodeMember = executeMember.provingAuth(summerInstance,member);
        //审核节点
        Integer auditNode = summerInstance.getNowNode();
        summerInstance.setNowNode(null);
        //获取审核记录
        SummerRecord record = this.createRecord(auditNode,null, SummerRecordResult.FAIL, opinion, nodeMember);
        this.saveToDb(summerInstance,record);
    }

    @Override
    public void back(Integer applyId, String apiPath, String member, String opinion) {
        this.back(applyId,apiPath,member,opinion,SummerBackType.START,null);
    }

    @Override
    public void backToLast(Integer applyId, String apiPath, String member, String opinion) {
        this.back(applyId,apiPath,member,opinion,SummerBackType.LAST,null);
    }

    @Override
    public void backToNode(Integer applyId, String apiPath, Integer nodeId, String member, String opinion) {
        this.back(applyId,apiPath,member,opinion,SummerBackType.ANYONE,nodeId);
    }



    /**
     * 获取审批实例
     * @param flowId 事件流id
     * @param applyId 申请id
     * @return 审批实例
     */
    private SummerInstance getInstanceByFlowIdAndApplyId(Integer flowId,Integer applyId){
        return summerInstanceMapper.selectByFlowIdAndApplyId(flowId,applyId);
    }

    /**
     * 创建一个审核节点记录
     * @param node 审核节点信息
     * @param nextNode 下一个节点信息
     * @param result 结果
     * @param opinion 意见
     * @param nodeMember 审核人信息
     * @return 生成的节点数据
     */
    private SummerRecord createRecord(Integer node,SummerNode nextNode ,SummerRecordResult result,String opinion,SummerNodeMember nodeMember){
        SummerRecord summerRecord = new SummerRecord();
        summerRecord.setNodeId(node);
        summerRecord.setResultId(result);
        summerRecord.setOpinion(opinion);
        //生成用户看到的审核结果。
        StringBuilder s = new StringBuilder();
        if (nextNode==null){
            switch (result){
                case PASS: s.append("通过");break;
                case FAIL: s.append("拒绝");break;
                case BACK: s.append("退回编辑");break;
                case PASS_TO_END: s.append("直接通过");break;
                default:{
                    throw new SummerExecuteException("审核结果异常。未匹配到正常类型。");
                }
            }
        }else {
            String nodeName = nextNode.getName();
            switch (result){
                case PASS:
                case PASS_TO_NODE :
                case SUBMIT: s.append("提交至节点");s.append(nodeName);break;
                case BACK_TO_LAST:
                case BACK_TO_NODE: s.append("退回至节点");s.append(nodeName);break;
                default:{
                    throw new SummerExecuteException("审核结果异常。未匹配到正常类型。");
                }
            }
        }
        summerRecord.setResult(s.toString());
        if (nodeMember!=null){
            summerRecord.setMemberId(nodeMember.getMemberId());
            summerRecord.setGroupId(nodeMember.getGroupId());
        }
        return summerRecord;
    }

    /**
     * 保存信息到数据库
     * @param instance 实例
     * @param record 审核记录
     */
    private void saveToDb(SummerInstance instance,SummerRecord record){
        //记录当前结果
        instance.setNowStatus(record.getResult());
        if (instance.getId()!=null){
            summerInstanceMapper.updateById(instance);
        }else {
            summerInstanceMapper.insert(instance);
        }
        //存储instanceId , 审核记录
        record.setInstanceId(instance.getId());
        summerRecordMapper.insert(record);
    }

    /**
     * 提交 ，启动流程
     * @param applyId 申请id
     * @param summerFlow 审核流
     * @param nodeId 节点id
     */
    private SummerAppoint start(Integer applyId,SummerFlow summerFlow,Integer nodeId){
        //是否可以指定审核人
        String errorMsg = null;
        if (!summerFlow.getIsAppointMember()){
            errorMsg = "该审核流不支持提交时指定审核人";
        }
        //获取审批流实例
        SummerInstance summerInstance= summerInstanceMapper.selectByApiPathAndApplyId(summerFlow.getApiPath(),applyId);
        if (summerInstance != null){
            throw new SummerExecuteException("该审核流实例已经存在，请使用restart方法重启实例流程。");
        }
        //新的实例
        summerInstance = new SummerInstance();
        summerInstance.setApplyId(applyId);
        summerInstance.setFlowId(summerFlow.getId());
        summerInstance.setStatus(SummerInstanceStatus.ONGOING);
        //获取节点
        SummerNode node ;
        if (nodeId == null){
            //第一个节点
            node = executeNode.getFirstNode(summerFlow.getId());
        }else {
            //指定节点
            node = executeNode.getAppointNode(nodeId);
            //记录提交的节点，重启流程时将自动跳到该节点
            summerInstance.setSubmitNode(nodeId);
        }
        //设置下一个审核节点
        summerInstance.setNowNode(node.getId());
        //创建审核记录
        SummerRecord summerRecord = this.createRecord(null,node,SummerRecordResult.SUBMIT,null,new SummerNodeMember("1"));
        this.saveToDb(summerInstance,summerRecord);
        return SummerAppoint.of(summerInstance,errorMsg,summerAppointMemberMapper,summerAppointMemberGlobalMapper,executeMember);
    }

    /**
     * 通过
     * @param applyId 申请id
     * @param apiPath 凭证
     * @param member  审核人
     * @param opinion 意见
     * @param nodeId  指定节点id
     */
    private SummerAppoint pass(Integer applyId, String apiPath, String member, String opinion, Integer nodeId){
        //指定审核人的错误信息
        String errorMsg = null;
        //检测审批流是否存在
        SummerFlow summerFlow = executeFlow.getUseFlow(apiPath);
        SummerInstance summerInstance = this.getInstanceByFlowIdAndApplyId(summerFlow.getId(),applyId);
        if (summerInstance == null){
            throw new SummerExecuteException("审核失败，该申请不存在");
        }
        //检测审核权限
        SummerNodeMember nodeMember = executeMember.provingAuth(summerInstance,member);
        //下一个节点
        SummerNode node ;
        if (nodeId==null){
            node = executeNode.getNextNode(summerInstance.getNode());
        }else {
            if (summerInstance.getNode().getType().equals(SummerNodeType.DEFAULT)){
                throw new SummerExecuteException("该节点不支持指定节点");
            }
            node = executeNode.getAppointNode(nodeId);
        }
        //为null 则是通过,
        Integer auditNode = summerInstance.getNowNode();
        if (node == null){
            summerInstance.setStatus(SummerInstanceStatus.PASS);
            summerInstance.setNowNode(null);
            errorMsg = "该实例已达最后一个节点，不能使用指定审核人";
        }else {
            summerInstance.setNowNode(node.getId());
        }
        //新建审核记录
        SummerRecord record = this.createRecord(auditNode,node, SummerRecordResult.PASS, opinion, nodeMember);
        this.saveToDb(summerInstance,record);
        return SummerAppoint.of(summerInstance,errorMsg,summerAppointMemberMapper,summerAppointMemberGlobalMapper,executeMember);
    }

    /**
     * 退回
     * @param applyId 申请id
     * @param apiPath 凭证
     * @param member 审核人
     * @param opinion 意见
     * @param backType 退回类型
     * @param nodeId 指定节点Id
     */
    private void back(Integer applyId, String apiPath, String member, String opinion,SummerBackType backType,Integer nodeId){
        //检测审批流是否存在
        SummerFlow summerFlow = executeFlow.getUseFlow(apiPath);
        SummerInstance summerInstance = this.getInstanceByFlowIdAndApplyId(summerFlow.getId(),applyId);
        if (summerInstance == null){
            throw new SummerExecuteException("审核失败，该申请不存在");
        }
        //结束事件流
        summerInstance.setStatus(SummerInstanceStatus.BACK);
        //检测审核权限
        SummerNodeMember nodeMember = executeMember.provingAuth(summerInstance,member);
        SummerNode nextNode = null;
        Integer auditNode = summerInstance.getNowNode();
        SummerRecordResult summerRecordResult = SummerRecordResult.BACK;
        //检测节点退回权限
        SummerBackType nodeType = summerInstance.getNode().getBackType();
        //如果当前节点不支持退回，抛出异常
        if (nodeType.equals(SummerBackType.NOT)){
            throw new SummerExecuteException("该节点不支持退回");
        }else if(nodeType.equals(SummerBackType.START)){
            if (backType!=SummerBackType.START){
                throw new SummerExecuteException("该节点只支持退回到提交人");
            }
            summerInstance.setStatus(SummerInstanceStatus.BACK);
        }else if (nodeType.equals(SummerBackType.LAST)){
            if (backType.equals(SummerBackType.ANYONE)){
                throw new SummerExecuteException("该节点不支持指定节点退回");
            }else if (backType.equals(SummerBackType.LAST)){
                //退回到上一个节点
                nextNode = executeNode.getLastNode(summerInstance.getNode());
                //如果上一个节点为Null 则 设置为暂停状态
                if (nextNode == null){
                    summerInstance.setStatus(SummerInstanceStatus.BACK);
                }else {
                    summerInstance.setNowNode(nextNode.getId());
                    summerRecordResult = SummerRecordResult.BACK_TO_LAST;
                }
            }else {
                //退回编辑
                summerInstance.setStatus(SummerInstanceStatus.BACK);
            }
        }else {
            if (backType.equals(SummerBackType.LAST)){
                //退回到上一个节点
                nextNode = executeNode.getLastNode(summerInstance.getNode());
                //如果上一个节点为Null 则 设置为暂停状态
                if (nextNode == null){
                    summerInstance.setStatus(SummerInstanceStatus.BACK);
                }else {
                    summerInstance.setNowNode(nextNode.getId());
                    summerRecordResult = SummerRecordResult.BACK_TO_LAST;
                }
            }else if (backType.equals(SummerBackType.ANYONE)){
                if (nodeId == null){
                    throw new SummerExecuteException("退回指定节点时，nodeId不能为空");
                }
                nextNode = executeNode.getAppointNode(nodeId);
                summerInstance.setNowNode(nextNode.getId());
                if (nextNode.getSort() >= summerInstance.getNode().getSort()){
                    throw new SummerExecuteException("退回指定节点不能在当前节点后面");
                }
                summerRecordResult = SummerRecordResult.BACK_TO_NODE;
            }
        }
        //获取审核记录
        SummerRecord record = this.createRecord(auditNode,nextNode, summerRecordResult, opinion, nodeMember);
        this.saveToDb(summerInstance,record);
    }
}
